#!/usr/bin/env python

"""Water Phase Change Example

#########                            ##########
#       #  >>> Condense (99*C)  >>>  #        #
# Vapor #                            # Liquid #
#       #  <<< Vaporize (101*C) <<<  #        #
#########                            ##########

##########                         #########
#        #  >>> Freeze (-1*C) >>>  #       #
# Liquid #                         # Solid #
#        #  <<< Melt   (1*C)  <<<  #       #
##########                         #########

"""
import time
from threading import Thread 
from fsm import FSM

# Temperature Constants (*C)
FREEZING_TEMP = -1
MELTING_TEMP = 1
VAPORIZING_TEMP = 101
CONDENSING_TEMP = 99

MAX_CYCLE_TEMP = 200
MIN_CYCLE_TEMP = -100
CYCLE_RATE = .1

# FSM Constants
ON_ENTER_ID = 0
ON_EXIT_ID = 1
TEMP_CHANGE_ID = 2
               
class Water():
    def __init__(self):
        # Water's Supported FSM Events
        #   Note that these events can be, nearly, any object
        ON_ENTER_EVT = (ON_ENTER_ID, None)
        ON_EXIT_EVT = (ON_EXIT_ID, None)
    
        # FSM Instance
        self.fsm = FSM(on_entry_event=ON_ENTER_EVT,
                       on_exit_event=ON_EXIT_EVT)
        
        # FSM Statates
        self.fsm.add_state("SOLID", self.__solid_handler)
        self.fsm.add_state("VAPOR", self.__vapor_handler)
        self.fsm.add_state("LIQUID", self.__liquid_handler)
        self.fsm.initialize("LIQUID")
        
        # FSM Stimuli
        self.water_temp = 25 # Room temp
        self.water_temp_rising = False
        
        self.water_temp_changer = Thread(target=self.__change_water_temp)
        self.water_temp_changer.daemon = True
        self.water_temp_changer.start()
        
    ## FSM Stimuli
    def __change_water_temp(self):
        while 1:
            # Heat / Cool the water
            if self.water_temp_rising:
                self.water_temp += CYCLE_RATE
            else:
                self.water_temp -= CYCLE_RATE
            
            # Cycle the heating / cooling of the water
            if self.water_temp >= MAX_CYCLE_TEMP:
                self.water_temp_rising = False
            elif self.water_temp <= MIN_CYCLE_TEMP:
                self.water_temp_rising = True
              
            # Create a new event passing the current water temp
            # to the current state
            TEMP_CHANGE_EVENT = (TEMP_CHANGE_ID, self.water_temp)
            
            # Dispatch the Water Temp Change Event
            self.fsm.dispatch(TEMP_CHANGE_EVENT)
            
            # Determine how fast the temperature should change
            time.sleep(.001)
       
    
    def __display_current_temp(self):
        print "\tTemp: %1.2f" % float(self.water_temp)
    
    ## FSM Event Handlers
    def __vapor_handler(self, event):
        event_id = event[0]
        event_data = event[1]
        
        # Note any actions done here will be performed for *ANY* event
        pass
        
        # Process Event Specific Data
        if event_id == ON_ENTER_ID:
            self.__display_current_temp()
            print "Entering the Vapor Phase!\n\n"

        elif event_id == ON_EXIT_ID:
            print "Leaving the Vapor Phase!"
            
        elif event_id == TEMP_CHANGE_ID:
            # Decode the event data
            water_tmp = event_data
            
            # Determine if a change in state is required
            if water_tmp < CONDENSING_TEMP:
                self.fsm.transition("LIQUID")
                
    def __liquid_handler(self, event):
        event_id = event[0]
        event_data = event[1]
        
        # Note any actions done here will be performed for *ANY* event
        pass
        
        # Process Event Specific Data
        if event_id == ON_ENTER_ID:
            self.__display_current_temp()
            print "Entering the Liqid Phase!\n\n"

        elif event_id == ON_EXIT_ID:
            print "Leaving the Liquid Phase!"
            
        elif event_id == TEMP_CHANGE_ID:
            # Decode the event data
            water_tmp = event_data
            
            # Determine if a change in state is required
            if water_tmp > VAPORIZING_TEMP:
                self.fsm.transition("VAPOR")
            elif water_tmp < FREEZING_TEMP:
                self.fsm.transition("SOLID")
        
    def __solid_handler(self, event):
        event_id = event[0]
        event_data = event[1]
        
        # Note any actions done here will be performed for *ANY* event
        pass
        
        # Process Event Specific Data
        if event_id == ON_ENTER_ID:
            self.__display_current_temp()
            print "Entering the Solid Phase!\n\n"
            
        elif event_id == ON_EXIT_ID:
            print "Leaving the Solid Phase!"
            
        elif event_id == TEMP_CHANGE_ID:
            # Decode the event data
            water_tmp = event_data
            
            # Determine if a change in state is required
            if water_tmp > MELTING_TEMP:
                self.fsm.transition("LIQUID")
        
if __name__ == "__main__":
    print "FSM Water Vapor Example:\nPress CTRL-C to exit\n\n"
    time.sleep(1)
    
    a_cup_of = Water()
    
    while(1):
        time.sleep(1)
    
    
    
    
        
    
